<template>
    <div ref="echartsRef" class="base-echart" :style="{ width, height }"></div>
</template>

<script setup lang="ts">
import echarts from '@/components/baseECharts/config'
import type { ECOption } from '@/components/baseECharts/config'
import { EchartsTheme } from '@/types/echarts'
import { number } from 'echarts'

interface Props {
    option?: echarts.EChartsCoreOption
    width?: string
    height?: string
    isAutoUpdate?: boolean
    theme?: any
    themeName?: EchartsTheme
    renderer?: 'canvas' | 'svg'
    initOpts?: echarts.EChartsInitOpts
}
const props = withDefaults(defineProps<Props>(), {
    width: '100%',
    height: '400px',
    isAutoUpdate: true,
    theme: macaronsTheme,
    themeName: 'macarons',
    renderer: 'canvas',
    initOpts: () => ({ renderer: 'canvas' }),
})

const echartsRef = ref<HTMLElement | null>(null)
// 图表实例
let echartsInstance: echarts.ECharts | null = null
// 使用 ResizeObserver 监听容器大小变化
let resizeObserver: ResizeObserver | null = null
// 初始化
const init = () => {
    if (!echartsRef.value) return
    dispose()
    // 初始化新实例
    echartsInstance = echarts.init(echartsRef.value, props.themeName, { ...props.initOpts, renderer: props.renderer })
    return echartsInstance ?? null
}
// 设置option
const setOption = (option: ECOption, params?: { isClear?: boolean; notMerge?: boolean; lazyUpdate?: boolean }) => {
    if (params?.isClear === true) clear()
    echartsInstance?.setOption(option, params?.notMerge, params?.lazyUpdate)
}
// 清空画布避免旧数据残留 (清理后数据动画会乱)
const clear = () => echartsInstance?.clear()
// 销毁旧的实例（如果有）
const dispose = () => {
    if (echartsInstance) {
        echartsInstance.dispose()
        echartsInstance = null
    }
}
// 注册地图
const registerMap = (name: string, map: any) => echarts.registerMap(name, map)
// 注册主题
const registerTheme = (name: string, theme: any) => echarts.registerTheme(name, theme)
// 获取实例
const getEChartsInstance = () => echartsInstance ?? null
// 重置大小，防抖处理
const resize = (opts?: echarts.ResizeOpts, timeout = 200, duration = 300) => {
    const setDebouncedValue = () => {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            echartsInstance?.resize({ ...opts, animation: { duration } })
        }, timeout)
    }
    setDebouncedValue()
}

// 初始化ResizeObserver
const initResizeObserver = () => {
    if (!echartsRef.value) return
    resizeObserver = new ResizeObserver(() => resize())
    // 同时监听容器及其父元素
    resizeObserver.observe(echartsRef.value)
    if (echartsRef.value.parentElement) {
        resizeObserver.observe(echartsRef.value.parentElement)
    }
}
// 断开连接
const disconnect = () => {
    if (resizeObserver) {
        resizeObserver.disconnect()
        resizeObserver = null
    }
}
// 深度监听 option 变化
watch(
    () => props.option,
    (newOption) => {
        if (props.isAutoUpdate && newOption) {
            setOption(newOption)
        }
    },
    {
        deep: true, // 深度监听
    },
)
// 挂载时初始化
onMounted(() => {
    registerTheme(props.themeName, props.theme)
    init()
    if (props.option) {
        setOption(props.option)
    }
    initResizeObserver()
})

// 卸载时销毁
onBeforeUnmount(() => {
    dispose()
    disconnect()
})
// 启用时重置大小
onActivated(() => {
    resize()
})

defineExpose({
    registerMap,
    registerTheme,
    init,
    setOption,
    getEChartsInstance,
    resize,
    clear,
    dispose,
})
</script>

<style lang="scss" scoped></style>
